/*
 * The contents of this web application are subject to the Mozilla Public License Version 
 * 1.1 (the "License"); you may not use this web application except in compliance with 
 * the License. You may obtain a copy of the License at http://www.mozilla.org/MPL/.
 * 
 * Software distributed under the License is distributed on an "AS IS" basis, 
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License 
 * for the specific language governing rights and limitations under the License.
 * 
 * The Original Code is owned by and the Initial Developer of the Original Code is 
 * Composite A/S (Danish business reg.no. 21744409). All Rights Reserved
 * 
 * Section 11 of the License is EXPRESSLY amended to include a provision stating 
 * that any dispute, including but not limited to disputes related to the enforcement 
 * of the License, to which Composite A/S as owner of the Original Code, as Initial 
 * Developer or in any other role, becomes a part to shall be governed by Danish law 
 * and be initiated before the Copenhagen City Court ("K�benhavns Byret")            
 */

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Xml.Linq;
using Composite.Core.IO;
using Composite.Core.Xml;

namespace Composite.Core.PackageSystem.PackageFragmentInstallers
{
	/// <summary>
	/// </summary>
	/// <exclude />
	[System.ComponentModel.EditorBrowsable(System.ComponentModel.EditorBrowsableState.Never)]
	public class XmlFileMergePackageFragmentUninstaller : BasePackageFragmentUninstaller
	{
		private sealed class XmlFileMerge
		{
			public string ChangeFilePath { get; set; }
			public string TargetPath { get; set; }
		}

		private IList<XmlFileMerge> _xmlFileMerges;

		/// <exclude />
		public override void Uninstall()
		{
			if (_xmlFileMerges == null) throw new InvalidOperationException("XmlFileMergePackageFragmentUninstaller has not been validated");

			foreach (XmlFileMerge xmlFileMerge in _xmlFileMerges)
			{
				string targetXml = PathUtil.Resolve(xmlFileMerge.TargetPath);

				using (Stream stream = this.UninstallerContext.ZipFileSystem.GetFileStream(xmlFileMerge.ChangeFilePath))
				{
					XElement source = XElement.Load(stream);
					XDocument target = XDocumentUtils.Load(targetXml);

					target.Root.RemoveMatches(source);
					target.SaveToFile(targetXml);
				}
			}
		}

		/// <exclude />
		public override IEnumerable<PackageFragmentValidationResult> Validate()
		{
			List<PackageFragmentValidationResult> validationResult = new List<PackageFragmentValidationResult>();

			if (Configuration.Count(f => f.Name == XmlFileMergePackageFragmentInstaller.mergeContainerElementName) > 1)
			{
				validationResult.Add(new PackageFragmentValidationResult(PackageFragmentValidationResultType.Fatal, "OnlyOneFilesElement"));

				return validationResult;
			}

			IEnumerable<XElement> filesElement = this.Configuration.Where(f => f.Name == XmlFileMergePackageFragmentInstaller.mergeContainerElementName);

			_xmlFileMerges = new List<XmlFileMerge>();

			foreach (var fileElement in filesElement.Elements(XmlFileMergePackageFragmentInstaller.mergeElementName))
			{
				XAttribute changePathAttribute = fileElement.Attribute(XmlFileMergePackageFragmentInstaller.changeDefFileAttributeName);
				XAttribute targetAttribute = fileElement.Attribute(XmlFileMergePackageFragmentInstaller.targetFileAttributeName);

				if (changePathAttribute == null || targetAttribute == null)
				{
					validationResult.Add(new PackageFragmentValidationResult(PackageFragmentValidationResultType.Fatal, "MissingAttribute", fileElement));

					continue;
				}

				XmlFileMerge xmlFileMerge = new XmlFileMerge
				{
					ChangeFilePath = changePathAttribute.Value,
					TargetPath = targetAttribute.Value
				};

				if (!C1File.Exists(PathUtil.Resolve(xmlFileMerge.TargetPath)))
				{
					validationResult.Add(new PackageFragmentValidationResult(PackageFragmentValidationResultType.Fatal, "FileNotFound", fileElement));

					continue;
				}

				_xmlFileMerges.Add(xmlFileMerge);
			}

			if (validationResult.Count > 0)
			{
				_xmlFileMerges = null;
			}

			return validationResult;
		}
	}
}
